package execute

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"
)

type ExecuteCommand struct {
	*exec.Cmd
	StdoutIn *bufio.Reader
	StderrIn *bufio.Reader
	StdIn    *bufio.Writer
	Ctx      context.Context
}

//new 一个命令
func New(ctx context.Context, name string, arg ...string) *ExecuteCommand {
	executeCommand := new(ExecuteCommand)
	executeCommand.Ctx = ctx
	executeCommand.Cmd = exec.CommandContext(ctx, name, arg...)
	StdoutPipe, _ := executeCommand.StdoutPipe()
	executeCommand.StdoutIn = bufio.NewReader(StdoutPipe)
	stderrIn, _ := executeCommand.StderrPipe()
	executeCommand.StderrIn = bufio.NewReader(stderrIn)
	stdin, _ := executeCommand.StdinPipe()
	executeCommand.StdIn = bufio.NewWriter(stdin)
	return executeCommand
}

//开始运行
func (executeCommand *ExecuteCommand) Run() error {

	//应该可以不写吧
	go func(ctx context.Context) {
		for {
			select {
			case <-ctx.Done():
				//log.Println("ctx.done")
				executeCommand.Process.Kill()
				return
				//if err := syscall.Kill(-1*pid, syscall.SIGKILL); err != nil {
				//	return
				//}
			default:
				time.Sleep(1 * time.Second)
			}
		}
	}(executeCommand.Ctx)

	err := executeCommand.Start()
	if err != nil {
		return err
	}
	executeCommand.ReadPipe()

	err = executeCommand.Wait()
	return err
}

func (executeCommand *ExecuteCommand) ReadPipe() {
	go func() {
		ReadPipe(executeCommand.StdoutIn)
	}()

	go func() {
		ReadPipe(executeCommand.StderrIn)
	}()

	go func() {
		var input string
		writer := executeCommand.StdIn
		for {
			scanln, err := fmt.Scanln(&input)
			if err != nil || scanln == 0 {
				continue
			}
			writer.WriteString(input + "\n")
			writer.Flush()
		}
	}()
}

func ReadPipe(reader *bufio.Reader) ([]byte, error) {

	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			// Read returns io.EOF at the end of file, which is not an error for us
			if err == io.EOF {
				err = nil
			}
			return line, err
		}
		os.Stdout.Write(append(line, []byte("\n")...))
	}
}
